package core
{
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import flash.utils.ByteArray;
	
	import org.ais.event.TEvent;

	public class Main extends Sprite
	{
		public var LOADING_MASK_SKIN:Function;
		public var LOADING_MASK_NAME:String;
		public var LOADING_MASK_COUNT:int;
		public var LOADING_COUNT:int;
		
		protected var appDomain:ApplicationDomain;
		
		public function Main()
		{
			try {
				Security.allowDomain("*");
				Security.allowInsecureDomain("*");
			}
			catch (error:*) {}
		}
		
		public function connect(im:*):void
		{
			LOADING_MASK_NAME = Math.random().toString();
			LOADING_MASK_SKIN = __loadingMaskSkin;
			
			appDomain = new ApplicationDomain(loaderInfo.applicationDomain);
			
			if (null !== im) {
				if (loaderInfo.parameters["assets"]) {
					var arr:Array = loaderInfo.parameters["assets"].replace(/^(\s*[\,]\s*)*|(\s*[\,]\s*)*$/, "").split(/\s*\,+\s*/);
					var arr2:Array;
					var lc:LoaderContext = new LoaderContext();
					var loader:Loader;
					for (var i:uint = 0, l:uint = arr.length; i < l; i++) {
						arr2 = arr[i].split(/\:+/);
						if (arr2.length === 1 || uint(arr2[1]) === 0) lc.applicationDomain = appDomain;
						else lc.applicationDomain = __getAppDomain(uint(arr2[1]));
						loader = new Loader();
						loader.contentLoaderInfo.addEventListener(Event.COMPLETE, __swfHandler);
						loader.loadBytes(im.Swf.get(arr2[0], "swf").contentLoaderInfo.bytes, lc);
						im.Swf.remove(arr2[0]);
					}
					arr = null;
					arr2 = null;
					lc = null;
					loader = null;
				}
			}
			im = null;
		}
		
		protected function __getAppDomain(p:uint = 0):ApplicationDomain
		{
			if (p === 0) return null;
			var a:ApplicationDomain = appDomain;
			for (; p > 1; p--) {
				if (null === a.parentDomain) return a;
				else a = a.parentDomain;
			}
			return a;
		}
		
		protected function __loadingMaskSkin():DisplayObject
		{
			var cls:Class = getClass("AISY_LOADING") as Class;
			var skin:DisplayObject;
			if (null !== cls) {
				skin = new (getClass("AISY_LOADING")as Class)();
				skin.width = skin.height = 70;
			}
			cls = null;
			return skin;
		}
		
		protected function __swfHandler(e:Event):void
		{
			e.currentTarget.removeEventListener(Event.COMPLETE, __swfHandler);
			e = null;
		}
		
		protected function getCallback(callback:Object, index:uint, key:String):Function
		{
			var cb:Function;
			if (callback is Function) cb = callback as Function;
			else if (callback is Array && callback[index] is Function) cb = callback[index];
			else if (callback is Object && callback[key] is Function) cb = callback[key];
			callback = null;
			key = null;
			return cb;
		}
		
		protected function applyCallback(args:Array, callback:Object, index:uint, key:String):Function
		{
			if (null === callback) return null;
			var cb:Function = getCallback(callback, index, key);
			if (null !== cb) cb.apply(null, args.slice(0, cb.length));
			args = null;
			callback = null;
			key = null;
			return cb;
		}
		
		/**
		 * 
		 * @param className
		 * @param asset
		 * @param callback [onComplete, onIoError, onProgress, onHttpStatus, onInit, onUnload]
		 * @param applicationDomain
		 * @return 
		 * 
		 */
		public function getClass(className:String, asset:Object = null, callback:Object = null, applicationDomain:uint = 1):Object
		{
			if (null !== className && appDomain.hasDefinition(className) === true) {
				var obj:Object = appDomain.getDefinition(className);
				applyCallback([obj, null, null], callback, 0, "onComplete");
				className = null;
				asset = null;
				callback = null;
				return obj;
			}
			else if (null !== asset) {
				LOADING_COUNT++;
				showLoadingMask();
				var isF:Boolean = callback is Function;
				var lc:LoaderContext = new LoaderContext();
				if (applicationDomain !== 0) lc.applicationDomain = __getAppDomain(applicationDomain);
				var arr:Array;
				var cb:Function;
				var f:Function = function (e:Event):void
				{
					arr = [e, loader];
					switch (e.type) {
						case Event.COMPLETE:
							LOADING_COUNT--;
							clearLoadingMask();
							arr.unshift(className === null ? null : loader.contentLoaderInfo.applicationDomain.getDefinition(className));
							cb = applyCallback(arr, callback, 0, "onComplete");
							if (applicationDomain === 0 && (null === cb || cb.length < 3)) loader.unload();
							cf(0);
							break;
						case IOErrorEvent.IO_ERROR:
							LOADING_COUNT--;
							applyCallback(arr, callback, 1, "onIoError");
							cf(2);
							break;
						case ProgressEvent.PROGRESS:
							applyCallback(arr, callback, 2, "onProgress");
							break;
						case HTTPStatusEvent.HTTP_STATUS:
							applyCallback(arr, callback, 3, "onHttpStatus");
							break;
						case Event.INIT:
							applyCallback(arr, callback, 4, "onInit");
							break;
						case Event.UNLOAD:
							applyCallback(arr, callback, 5, "onUnload");
							cf(1);
							break;
					}
					arr = null;
					cb = null;
					e = null;
				};
				var af:Function = function (index:uint, key:String, type:String):void
				{
					if (null !== getCallback(callback, index, key)) loader.contentLoaderInfo.addEventListener(type, f);
					key = null;
					type = null;
				};
				var rf:Function = function (index:uint, key:String, type:String):void
				{
					if (null !== getCallback(callback, index, key)) loader.contentLoaderInfo.removeEventListener(type, f);
					key = null;
					type = null;
				};
				var cf:Function = function (type:int):void
				{
					switch (type) {
						case 0:
							loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, f);
							if (null !== callback) {
								if (isF === false) {
									rf(1, "onIoError", IOErrorEvent.IO_ERROR);
									rf(2, "onProgress", ProgressEvent.PROGRESS);
									rf(3, "onHttpStatus", HTTPStatusEvent.HTTP_STATUS);
									rf(4, "onInit", Event.INIT);
								}
							}
							if (null === callback || isF === true || (isF === false && null === getCallback(callback, 5, "onUnload"))) {
								f = null;
								af = null;
								rf = null;
								cf = null;
								loader = null;
								callback = null;
							}
							className = null;
							break;
						case 1:
							if (null !== callback) if (isF === false) rf(5, "onUnload", Event.UNLOAD);
							f = null;
							af = null;
							rf = null;
							cf = null;
							loader = null;
							callback = null;
							break;
						case 2:
							loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, f);
							if (null !== callback) {
								if (isF === false) {
									rf(1, "onIoError", IOErrorEvent.IO_ERROR);
									rf(2, "onProgress", ProgressEvent.PROGRESS);
									rf(3, "onHttpStatus", HTTPStatusEvent.HTTP_STATUS);
									rf(4, "onInit", Event.INIT);
									rf(5, "onUnload", Event.UNLOAD);
								}
							}
							f = null;
							af = null;
							rf = null;
							cf = null;
							loader = null;
							callback = null;
							className = null;
							break;
					}
				};
				var loader:Loader = new Loader();
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, f);
				if (null !== callback && (callback is Function) === false) {
					af(1, "onIoError", IOErrorEvent.IO_ERROR);
					af(2, "onProgress", ProgressEvent.PROGRESS);
					af(3, "onHttpStatus", HTTPStatusEvent.HTTP_STATUS);
					af(4, "onInit", Event.INIT);
					af(5, "onUnload", Event.UNLOAD);
				}
				if (asset is String) loader.load(new URLRequest(String(asset)), lc);
				else if (asset is URLRequest) loader.load(asset as URLRequest, lc);
				else loader.loadBytes(asset as ByteArray, lc);
				lc = null;
				asset = null;
			}
			else if (null !== callback) callback.apply(null, [null, null].slice(0, callback.length));
			return null;
		}
		
		public function showLoadingMask():void
		{
			if (LOADING_MASK_COUNT === 0) {
				var skin:DisplayObject = LOADING_MASK_SKIN();
				if (null !== skin) TEvent.trigger("UP_WINDOW_AIS", "SHOW", [skin, LOADING_MASK_NAME, 2, false, false, 0, 0, 0, false]);
				skin = null;
			}
			LOADING_MASK_COUNT++;
		}
		
		public function clearLoadingMask():void
		{
			LOADING_MASK_COUNT--;
			if (LOADING_MASK_COUNT <= 0) {
				LOADING_MASK_COUNT = 0;
				TEvent.trigger("UP_WINDOW_NEW", "CLEAR", {"name": LOADING_MASK_NAME});
			}
		}
		
		public function clear():void
		{
			appDomain = null;
			LOADING_MASK_SKIN = null;
			LOADING_MASK_NAME = null;
		}
		
	}
}